﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.Configuration;
using System.Diagnostics;
using System.IO;

namespace RGG.sharp
{
    /// <summary>
    ///     几何体的配置类
    /// </summary>
    //单例模式
    [Serializable]
    public class GeometricBodyConfig
    {
        private static GeometricBodyConfig _instance;
        private static readonly Object ObjLock = new object();
        private List<GeometricBodyConfigItem> _items = new List<GeometricBodyConfigItem>();

        private GeometricBodyConfig()
        {
        }

        public List<GeometricBodyConfigItem> Items
        {
            get { return _items; }
            set
            {
                _items = value;
                Items.RemoveAll(x => !x.Enable);
            }
        }
        /// <summary>
        /// 保存对配置的更改
        /// </summary>
        public void StoreAsFile()
        {
            var configFilePath = ConfigurationManager.AppSettings["GeometricBodyConfigPath"];
            var xmlSerializer = new XmlSerializer(typeof(GeometricBodyConfig));
            if (File.Exists(configFilePath))
            {
                File.Delete(configFilePath);
            }
            xmlSerializer.Serialize(new FileStream(configFilePath, FileMode.Create, FileAccess.Write), this);
        }
        
        /// <summary>
        /// 获取对象的实例
        /// </summary>
        /// <returns></returns>
        public static GeometricBodyConfig GetInstance()
        {
            if (_instance == null)
            {
                GeometricBodyConfig gbc = null;
                string configFilePath = ConfigurationManager.AppSettings["GeometricBodyConfigPath"];
                Debug.Assert(configFilePath != null, "需要在App.config文件里面的AppSettings节的子节GeometricBodyConfigPath");
                if (File.Exists(configFilePath))
                {
                    XmlSerializer xmlserializer = new XmlSerializer(typeof (GeometricBodyConfig));
                    gbc =
                        xmlserializer.Deserialize(new FileStream(configFilePath, FileMode.Open, FileAccess.Read)) as
                            GeometricBodyConfig;
                    Debug.Assert(gbc.Items.TrueForAll(x=>x.Width*x.Height == x.DotMatrix.Count),"对象长和高的乘积必须与点阵的长度相等！");
                    lock (ObjLock)
                    {
                        if (_instance == null)
                        {
                            _instance = gbc;
                        }
                    }
                }
                else
                {
                    ResetConfigFile();
                }
            }
            return _instance;
        }
        /// <summary>
        /// 重置配置文件，该函数会重置_instance对象
        /// </summary>
        private static void ResetConfigFile()
        {
            GeometricBodyConfig config = null;
            config = new GeometricBodyConfig
            {
                Items = new List<GeometricBodyConfigItem>
                {
                    new GeometricBodyConfigItem
                    {
                        ClassName = "LinePiece",
                        ColorGB = Color.Blue,
                        DotMatrix = new List<int> {1, 1, 1, 1},
                        Enable = true,
                        Height = 4,
                        Width = 1
                    },
                    new GeometricBodyConfigItem
                    {
                        ClassName = "Square",
                        ColorGB = Color.Red,
                        DotMatrix = new List<int> {1, 1, 1, 1},
                        Enable = true,
                        Height = 2,
                        Width = 2
                    },
                    new GeometricBodyConfigItem
                    {
                        ClassName = "Swagerly",
                        ColorGB = Color.Green,
                        DotMatrix = new List<int> {0, 1, 1, 1, 1, 0},
                        Enable = true,
                        Height = 3,
                        Width = 2
                    },
                    new GeometricBodyConfigItem
                    {
                        ClassName = "ReverseSwagerly",
                        ColorGB = Color.GreenYellow,
                        DotMatrix = new List<int> {1,0,1,1,0,1},
                        Enable = true,
                        Height = 3,
                        Width = 2
                    }
                    ,
                    new GeometricBodyConfigItem
                    {
                        ClassName = "LBlock",
                        ColorGB = Color.Lavender,
                        DotMatrix = new List<int> {1,1,1,1,0,0},
                        Enable = true,
                        Height = 2,
                        Width = 3
                    },
                    new GeometricBodyConfigItem
                    {
                        ClassName = "ReverseLBlock",
                        ColorGB = Color.MediumBlue,
                        DotMatrix = new List<int> {1,1,1,0,0,1},
                        Enable = true,
                        Height = 2,
                        Width = 3
                    },
                    new GeometricBodyConfigItem
                    {
                        ClassName = "TBlock",
                        ColorGB = Color.MediumBlue,
                        DotMatrix = new List<int> {1,0,1,1,1,0},
                        Enable = true,
                        Height = 3,
                        Width = 2
                    }
                }
            };
            _instance = config;
            config.StoreAsFile();
        }
    }


    [Serializable]
    public class GeometricBodyConfigItem : IXmlSerializable
    {
        private string _className = "GB";
        private Color _colorGb = Color.FromArgb(0000000);
        private List<int> _dotMatrix = new List<int>();
        private bool _enable = true;
        private int _height;
        private int _width;

        public bool Enable
        {
            get { return _enable; }
            set { _enable = value; }
        }

        public List<int> DotMatrix
        {
            get { return _dotMatrix; }
            set { _dotMatrix = value; }
        }

        public string ClassName
        {
            get { return _className; }
            set { _className = value; }
        }

        public int Width
        {
            get { return _width; }
            set { _width = value; }
        }

        public int Height
        {
            get { return _height; }
            set { _height = value; }
        }

        public Color ColorGB
        {
            get { return _colorGb; }
            set { _colorGb = value; }
        }

        /// <summary>
        /// </summary>
        /// <returns>返回null</returns>
        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {
            if (reader.Name != "GeometricBodyConfigItem")
            {
                reader.ReadToDescendant("GeometricBodyConfigItem");
            }
            if (reader.NodeType != XmlNodeType.EndElement)
            {
//找到一个以上GeometricBodyConfigItem
                reader.ReadToDescendant("ClassName");
                ClassName = reader.ReadString();
                reader.ReadEndElement();
                reader.ReadStartElement("Enable");
                Enable = bool.Parse(reader.ReadString());
                reader.ReadEndElement();
                reader.ReadStartElement("Width");
                Width = int.Parse(reader.ReadString());
                reader.ReadEndElement();
                reader.ReadStartElement("Height");
                Height = int.Parse(reader.ReadString());
                reader.ReadEndElement();
                reader.ReadStartElement("Color");
                var colorString = reader.ReadString();
                var regex = new Regex("^[0-9a-fA-F]{6,8}$");
                if (regex.IsMatch(colorString))
                {
                    ColorGB = Color.FromArgb(int.Parse(colorString, NumberStyles.HexNumber));
                }
                else
                {
                    ColorGB = Color.FromName(colorString);
                }
                reader.ReadEndElement();
                reader.ReadStartElement("DotMatrix");
                DotMatrix = reader.ReadString().ToCharArray().Select(x => x - '0').ToList();
                reader.ReadEndElement();
                reader.ReadEndElement();
            }
        }

        public void WriteXml(XmlWriter writer)
        {
            writer.WriteElementString("ClassName", ClassName);
            writer.WriteElementString("Enable", Enable.ToString());
            writer.WriteElementString("Width", Width.ToString());
            writer.WriteElementString("Height", Height.ToString());
            writer.WriteElementString("Color", ColorGB.ToArgb().ToString("X8"));
            var sb = new StringBuilder();
            foreach (var i in DotMatrix)
            {
                sb.Append(i);
            }
            writer.WriteElementString("DotMatrix", sb.ToString());
        }
    }
}